; Interfaces to the storage mechanisms for filing system directories

; Current storage mechanism uses system variables:

; FileSwitch$<FS>$CSD
; FileSwitch$<FS>$PSD
; FileSwitch$<FS>$Lib
; FileSwitch$<FS>$URD

        ; Craps on r1-r3,lr
        ; $fscb - fscb^ for sysvar
        ; $which - which directory (@, %, & or \)
        ; $stackfvar - register which contains current stack adjust and will be updated
        ;
        ; Out with sysvar name constructed on stack
        MACRO
        ConstructSysvarNameOnStack $fscb,$which,$stackfvar
        ; Evaluate stack space needed for name
        ADD     r1, $fscb, #fscb_name
        BL      strlen
        ADD     r3, r3, #?FSW_Sysvar_Prefix + ?FSW_CSD_Suffix + 1 + 3
        BIC     r3, r3, #3

        ; Get the stack space
        SUB     sp, sp, r3
        ADD     $stackfvar, $stackfvar, r3

        ; Construct the name
        MOV     r1, sp
        addr    r2, FSW_Sysvar_Prefix
        BL      strcpy_advance
        ADD     r2, $fscb, #fscb_name
        BL      strcpy_advance
        addr    r2, FSW_Sysvar_Suffixes
        LDR     r2, [r2, $which, ASL #2]
        addr    lr, Module_BaseAddr
        ADD     r2, r2, lr
        BL      strcpy_advance
        MEND

FSW_Sysvar_Suffixes
        DCD     FSW_CSD_Suffix - Module_BaseAddr
        DCD     FSW_PSD_Suffix - Module_BaseAddr
        DCD     FSW_URD_Suffix - Module_BaseAddr
        DCD     FSW_Lib_Suffix - Module_BaseAddr

FSW_Sysvar_Prefix DCB   "FileSwitch$"
        DCB     0

FSW_CSD_Suffix DCB "$CSD"
        DCB     0
FSW_PSD_Suffix DCB "$PSD"
        DCB     0
FSW_URD_Suffix DCB "$URD"
        DCB     0
FSW_Lib_Suffix DCB "$Lib"
        DCB     0
        ALIGN

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; SimpleReadDir
;
; In    r1 = pointer to buffer
;       r2 = which dir to read
;       r5 = size of buffer
;       fscb
;
; Out   r1 = 0 if not found
;       r5 reduced by length of variable

SimpleReadDir ENTRY    "r0-r8", 512

        MOV     r8, sp
        MOV     r7, #0
        MOV     r6, r2

        ConstructSysvarNameOnStack fscb, r6, r7

        MOV     r0, sp
        MOV     r1, r8
        MOV     r2, #Proc_LocalStack
        SUB     r2, r2, #1      ; leave room for nul terminator
        MOV     r3, #0          ; We know what the name is
        MOV     r4, #VarType_Expanded ; Expand macros in variable
        SWI     XOS_ReadVarVal
        MOV     sp, r8

        MOVVS   r1, #0
        BVS     %FT90

        MOV     r1, sp
        MOV     lr, #0
        STRB    lr, [r1, r2]    ; \0-terminate the string
        MOV     r3, #1
        BL      strlen_accumulate
        SUBS    r5, r5, r3

        LDRGE   r1, [sp, #Proc_LocalStack + 1*4]
        MOVGE   r2, sp
        BLGE    strcpy

        STR     r5, [sp, #Proc_LocalStack + 5*4]

90
        STR     r1, [sp, #Proc_LocalStack + 1*4]

        EXITS

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ReadDirWithSuppliedDefault
;
; In    r0 = pointer to linked string root
;       r2 = which directory
;       r3 = default
;       fscb (non-MultiFS)
;
; Out   error possible
;
; Returns path corresponding to directory, or NULL if unset
;
ReadDirWithSuppliedDefault ENTRY "r0-r3,r6-r8"

 [ debugdirstore
 DREG r2, "Reading dir "
 ]
        ; Construct sysvar name

        MOV     r8, sp
        MOV     r7, #0
        MOV     r6, r2

        ConstructSysvarNameOnStack fscb, r6, r7

        ; Get the variable
        MOV     r0, sp
 [ debugdirstore
 DSTRING r0, "Reading dirstore "
 ]
        LDR     r3, [r8, #Proc_LocalStack + 3*4]
        BL      SReadVariableToBuffer
        ADD     r7, r7, r2
        BVS     %FT90

        ; Convert to linked string
        LDR     r0, [r8, #Proc_LocalStack + 0*4]
        MOV     r1, sp
 [ debugdirstore
 DSTRING r1, "Getting linked string "
 ]
        BL      SGetLinkedString

90
        ; Drop the dynamic stack frames
        ADD     sp, sp, r7
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ReadDirWithDefault
;
; In    r0 = pointer to linked string root
;       r1 = 0 or 1 to include/remove any | prefix
;       r2 = which directory
;       fscb (non-MultiFS)
;
; Out
;
; Returns path corresponding to directory, or default if unset.
;
; Defaults are:
; @ - $
; \ - $
; & - $
; % - &.Library,$.Library,@
;
ReadDirWithDefault ENTRY "r3"
        LDR     lr, [fscb, #fscb_info]
        TST     lr, #fsinfo_handlesurdetc
        ADREQ   lr, DirDefaultTab
        ADRNE   lr, DirWhanDefaultTab
        LDR     r3, [lr, r2, ASL #2]
        addr    lr, Module_BaseAddr
        ADD     r3, r3, lr
        LDRB    lr, [r3]
        TEQ     lr, #"|"
        TEQEQ   r1, #1
        ADDEQ   r3, r3, #1
        BL      ReadDirWithSuppliedDefault
        EXIT

DirDefaultTab
        DCD     CSD_Default - Module_BaseAddr
        DCD     PSD_Default - Module_BaseAddr
        DCD     URD_Default - Module_BaseAddr
        DCD     Lib_Default - Module_BaseAddr
DirWhanDefaultTab
        DCD     CSD_Whan_Default - Module_BaseAddr
        DCD     PSD_Whan_Default - Module_BaseAddr
        DCD     URD_Whan_Default - Module_BaseAddr
        DCD     Lib_Whan_Default - Module_BaseAddr

CSD_Default
        DCB     "$", 0
PSD_Default
        DCB     "$", 0
URD_Default
        DCB     "$", 0
Lib_Default
        DCB     "|&.Library|$.Library|@", 0
CSD_Whan_Default
        DCB     "|&", 0
PSD_Whan_Default
        DCB     "|&", 0
URD_Whan_Default
        DCB     "|&", 0
Lib_Whan_Default
        DCB     "|&.Library|$.Library|@", 0
        ALIGN

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ExpandingReadDirWithDefault
;
; In    r0 = pointer to linked string root
;       r2 = which directory
;       fscb (non-MultiFS)
;
; Out   error possible
;
; Does a ReadDirWithDefault, expanding references to other dirs.
; Expansion is very limited: it only expands @ and & (in that order).
; This limitation is on purpose: its is designed to handle multi-option
; % only, which should be supplied internally only.
;
ExpandingReadDirWithDefault ENTRY "r0,r1,r2,r3"
        MOV     r1, #0
        BL      ReadDirWithDefault
        EXIT    VS

        ; Check for & and @ substitution
        LDR     r1, [r0]
        LDRB    lr, [r1]
        TEQ     lr, #"|"
        EXIT    NE

        ; Remove | prefix and substitute for & and @
        ADD     r2, r1, #1
        BL      strcpy
        MOVVC   r2, #Dir_Current
        MOVVC   r3, #"@"
        BLVC    ExpandOneDir
        MOVVC   r2, #Dir_UserRoot
        MOVVC   r3, #"&"
        BLVC    ExpandOneDir

        EXIT

ExpandOneDir ENTRY "r0-r4", 8

 [ debugdirstore
 DREG r2, "Expanding dir ",cc
 DREG r3, " with char "
 ]

        ; Find the char to substitute
        LDR     r1, [r0]
        MOV     r0, r3
        BL      strchr
        EXIT    NE
        MOV     r4, r1

        ; Get the dirstring for that char
        ADD     r0, sp, #0*4
        MOV     r1, #1
        BL      ReadDirWithDefault
        EXIT    VS

        ; Find out how much space is needed
        LDR     r1, [r0]
        BL      strlen                  ; New string
        LDR     r0, [sp, #Proc_LocalStack + 0*4]
        LDR     r1, [r0]
        BL      strlen_accumulate       ; old string (includes substitued char, hence no correction of \0)

 [ debugdirstore
 DREG r3, "Space needed "
 ]

        ; Get the string
        ADD     r0, sp, #1*4
 [ debugheap
        DLINE   "ExpandOneDir:",cc
 ]
        BL      SGetLinkedArea
        BVS     %FT80

        ; Stick a \0 at the expanded dir char place
        MOV     lr, #0
        STRB    lr, [r4]

        ; Copy the string bits together
        MOV     r1, r2
        LDR     r2, [sp, #Proc_LocalStack + 0*4]
        LDR     r2, [r2]
        BL      strcpy_advance          ; Prefix
        LDR     r2, [sp, #0*4]
        BL      strcpy_advance          ; alternative to dir char
        ADD     r2, r4, #1
        BL      strcpy_advance          ; suffix

        ; Free the old Dir
        LDR     r0, [sp, #Proc_LocalStack + 0*4]
        BL      SFreeLinkedArea

        ; Replace with the new if OK
        LDRVC   r2, [sp, #1*4]
        STRVC   r2, [r0]
 [ debugdirstore
 DSTRING r2, "Constructed string is "
 ]

80
        ; Free the substituted string
        ADD     r0, sp, #0*4
        BL      SFreeLinkedArea
90
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ReadDir
;
; In    r0 = pointer to linked string root
;       r2 = which directory
;       fscb (non-MultiFS)
;
; Out   error possible
;
; Reads the requested directory. Defaults do apply, result will be valid path.
;
        ^ 0,sp
ReadDir_Path # 4
ReadDir_Special # 4
ReadDir_LocalSize * :INDEX:{VAR}

ReadDir ENTRY   "r0-r9,fscb", ReadDir_LocalSize
 [ debugdirstore
 DREG r0, "Read dirstore to "
 ]

        BL      ExpandingReadDirWithDefault
        EXIT    VS
        MOV     r8, r0

05
        MOV     r1, #0
        STR     r1, ReadDir_Path
        STR     r1, ReadDir_Special

        LDR     r1, [r8]
        MOV     r0, #"|"
        BL      strchr
        BNE     %FT40

        ; Take a copy of path and special

        ; Terminate at the '|'
        MOV     r0, #0
        STRB    r0, [r1]
        ADD     r9, r1, #1      ; preserve break position

        ; Check for special field
        LDR     r6, [r8]
        LDRB    r0, [r6], #1
        TEQ     r0, #"#"
        ADDNE   r7, r6, #-1     ; Start of real path
        MOVNE   r6, #NULL       ; No special field
        BNE     %FT10

        ; Special field probably present
        MOV     r1, r6
        MOV     r0, #":"
        BL      strchr
        BNE     %FT20           ; Duff special field - reject whole path element

        ; Special field good - break at ':' and copy it
        MOV     r0, #0
        STRB    r0, [r1], #1
        MOV     r7, r1

        ; Copy the special
        ADR     r0, ReadDir_Special
        MOV     r1, r6
        BL      SGetLinkedString
        BVS     %FT90

10
        ; Copy the path
        ADR     r0, ReadDir_Path
        MOV     r1, r7
        BL      SGetLinkedString
        BVS     %FT90

        ; Canonicalise it and ensure it
        ADR     r1, ReadDir_Path
        MOV     r3, #0                  ; @-relativity
        ADR     r6, ReadDir_Special
        LDR     fscb, [sp, #Proc_LocalStack + 10*4]
        BL      EnsureObjectCommon
        BVS     %FT90

        ; If exists leave loop and use this
        TEQ     r0, #object_nothing
        BNE     %FT30

20
        ; Duff path element - try next

        ; Free the two strings
        ADR     r0, ReadDir_Path
        BL      SFreeLinkedString
        ADR     r0, ReadDir_Special
        BL      SFreeLinkedString
        BVS     %FT90

        ; Copy rest of path down
        LDR     r1, [r8]
        MOV     r2, r9
        BL      strcpy

        ; Go round for another go
        B       %BT05

30
        ; Everything hunky-dory, construct proper path

        ; Count how much space needed
        MOV     r2, #ARM_CC_Mask
        MOV     r3, #0
        BL      int_ConstructPathWithoutFS
        RSB     r7, r3, #1+3
        BIC     r7, r7, #3
        SUB     sp, sp, r7

        ; Actually construct the path
        MOV     r2, sp
        MOV     r3, r7
        BL      int_ConstructPathWithoutFS

        ; Replace with this path
        MOV     r0, r8
        MOV     r1, sp
        BL      SNewLinkedString
        ADD     sp, sp, r7

        ; Free the two strings
        ADR     r0, ReadDir_Path
        BL      SFreeLinkedString
        ADR     r0, ReadDir_Special
        BL      SFreeLinkedString

40
        ; Use first path element

        EXIT

90
        ; Error - free up dir and strings
        MOV     r0, r8
        BL      SFreeLinkedString
        ADR     r0, ReadDir_Special
        BL      SFreeLinkedString
        ADR     r0, ReadDir_Path
        BL      SFreeLinkedString

95
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; SetDirFromObject
;
; In    r1 = point to path tail
;       r2 = which directory
;       r6 = special field^/scb^
;       fscb
;
; Out   error possible
;
; Sets the directory to be the given object
;
SetDirFromObject ENTRY "r0-r8"
 [ debugdirstore
 DSTRING r1, "Setting dirstore with string "
 ]

        MOV     r8, sp
        MOV     r7, #0

        MOV     r2, #ARM_CC_Mask
        MOV     r3, #0
        BL      int_ConstructPathWithoutFS

        ; Get stack frame for value
        RSB     r3, r3, #3+1
        BIC     r7, r3, #3
        SUB     sp, sp, r7

        ; Rest of path
        LDR     r1, [r8, #Proc_LocalStack + 1*4]
        MOV     r2, sp
        MOV     r3, r7
        BL      int_ConstructPathWithoutFS

        ; Save start of varval for later
        MOV     r4, sp

        ; Construct Sysvar name
        LDR     r6, [r8, #Proc_LocalStack + 2*4]
 [ debugdirstore
 DREG r5, "fscb is "
 DREG r6,"Constructing var number "
 ]
        ConstructSysvarNameOnStack r5, r6, r7

        ; Set the variable
        MOV     r0, sp
        MOV     r1, r4
 [ debugdirstore
 DSTRING r0, "Setting ",cc
 DSTRING r1, " to "
 ]
        MOV     r4, #VarType_String
        BL      SSetVariable

90
        ADD     sp, sp, r7
95
        BLVS    CopyErrorExternal
        STRVS   r0, [sp]                ; SBP: error was not getting passed back
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; UnsetDir
;
; In    r2 = which directory
;       fscb (non-MultiFS)
;
; Out   error possible
;
; Unsets the directory
;
UnsetDir ENTRY
        LDR     lr, [fscb, #fscb_info]
        TST     lr, #fsinfo_handlesurdetc
        BEQ     %FT10

        ; If handles URD etc and trying to unset UserRoot or Lib, then barf
        TEQ     r2, #Dir_UserRoot
        BLEQ    SetMagicCantSetLibOrURD
        EXIT    VS

10
        BL      int_UnsetDir
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; int_UnsetDir
;
; In    r2 = which directory
;       fscb (non-MultiFS)
;
; Out   error possible
;
; Unsets the directory without checking whether the filing system allows
; that directory to be set or not.
;
int_UnsetDir ENTRY "r0-r4,r6-r8"
        MOV     r8, sp
        MOV     r7, #0
        MOV     r6, r2
        ConstructSysvarNameOnStack fscb, r6, r7
        MOV     r0, sp
        MOV     r1, #NULL
        MOV     r4, #VarType_String
        BL      SSetVariable
        ADD     sp, sp, r7
        BLVS    CopyErrorExternal
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyDir
;
; In    r2 = destination
;       r3 = source
;       r6 = special field^/scb^
;       fscb
;
; Out   error possible
;
CopyDir ENTRY "r0-r8,fscb"
        MOV     r8, sp
        MOV     r7, #0
        BL      fscbscbTofscb

        MOV     fscb, r2
        MOV     r6, r3
        ConstructSysvarNameOnStack fscb, r6, r7

        ; Source varname
        MOV     r6, sp

        LDR     r5, [r8, #Proc_LocalStack + 2*4]
        ConstructSysvarNameOnStack fscb, r5, r7

        ; Destination varname
        MOV     r5, sp

        ; Read the source
        MOV     r0, r6
        addr    r3, anull
        BL      SReadVariableToBuffer
        ADD     r7, r7, r2
        BVS     %FT90

        ; Translate empty string to NULL
        LDRB    lr, [r1]
        TEQ     lr, #0
        MOVEQ   r1, #NULL

        MOV     r0, r5
        MOV     r4, #VarType_String
        BL      SSetVariable
        BLVS    CopyErrorExternal
        BVS     %FT90

        ADD     lr, sp, r7
        LDR     fscb, [lr, #9*4]
        LDR     r2, [lr, #2*4]

        ; Inform parent, if appropriate, of change to dir
        LDR     lr, [fscb, #fscb_extra]
        TST     lr, #fsextra_dirinformation

        MOVNE   r0, #fsfunc_DirIs
        BLNE    CallFSFunc_Given

90
        ADD     sp, sp, r7
        EXIT


; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ChangeDirectory
;
; In    r1 = path^
;       r2 = which directory
;
; Out   error or directory changed
;       r7 = 0 if no FS specified ultimately
;       fscb^

Default_CSD DCB "&", 0
Default_PSD DCB "@", 0
Default_Lib DCB "&", 0
Default_URD DCB "$", 0

ChangeDirectory ENTRY "r0-r6"
        ; Check for "" directory setting
        LDRB    r14, [r1]
        CMP     r14, #space-1
        TEQHS   r14, #delete
        BHI     %FT05

        ; Choose the relevant default
        TEQ     r2, #Dir_Current
        addr    r1, Default_CSD, EQ
        TEQ     r2, #Dir_Previous
        addr    r1, Default_PSD, EQ
        TEQ     r2, #Dir_Library
        addr    r1, Default_Lib, EQ
        TEQ     r2, #Dir_UserRoot
        addr    r1, Default_URD, EQ

05
        ; Find the object
        ADR     r0, PassedFilename
        MOV     r2, #NULL
        addr    r3, anull
        ADR     r4, FullFilename
        MOV     r5, #0
        ADR     r6, SpecialField
        BL      TopPath_DoBusinessToPathFSPrefix
        EXIT    VS

        Push    "r1,r2,r5"
        LDR     r1, PassedFilename
        LDR     r2, FullFilename
        MOV     r5, #0
        BL      TopPath_EnsureThingIsDirectory
        Pull    "r1,r2,r5"
        BVS     %FT90

10
        ; It's a directory - check filing system can have that directory set!
        LDR     r2, [sp, #Proc_LocalStack + 2*4]

        LDR     r14, [fscb, #fscb_info]
        TST     r14, #fsinfo_handlesurdetc
        BEQ     %FT20

        TEQ     r2, #Dir_UserRoot
        BLEQ    SetMagicCantSetLibOrURD
        BVS     %FT90

20
        TEQ     r2, #Dir_Current
        BNE     %FT30

        ; Copy @ to \ for setting @
        MOV     r2, #Dir_Previous
        MOV     r3, #Dir_Current
        BL      CopyDir

30
        LDR     r2, [sp, #Proc_LocalStack + 2*4]
        BL      SetDirFromObject
;        BLVS    CopyError    SBP: This was looking up a message token
        BVS     %FT90

        ; Inform parent, if appropriate, of change to dir
        LDR     lr, [fscb, #fscb_extra]
        TST     lr, #fsextra_dirinformation

        MOVNE   r0, #fsfunc_DirIs
        BLNE    CallFSFunc_Given
        BVS     %FT90

40
        BL      fscbscbTofscb
        MOV     fscb, r2

90
        BL      JunkFileStrings
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; DisplayDirectoryPath
;
; In    r0 = tag of string to display path in
;       r1 = tag of string if "Unset"
;       r2 = directory to display
;       fscb^ set to a non-MultiFS
;
; Out   Directory path OS_WriteCed
;
DisplayDirectoryPath ENTRY "r0-r7"
        GetLumpOfStack r5, #MaxFilenameSpace, #MaxFilenameSpace, #2048, %FA95

        ; Save dir to display for later
        MOV     r6, r2

        ; Save start of full path
        MOV     r4, sp

        ; <fs>:
        MOV     r1, sp
        ADD     r2, fscb, #fscb_name
        BL      strcpy_advance
        MOV     r0, #":"
        STRB    r0, [r1], #1
        SUB     lr, r1, sp      ; Amount of buffer used
        SUB     r7, r5, lr      ; Amount left

        MOV     r0, r1
        ConstructSysvarNameOnStack fscb,r6,r5
        MOV     r1, r0

        ; Read the directory variable
        MOV     r0, sp
 [ debugdirstore
        DSTRING r4, "Constructed path is "
        DREG    r4, " at "
        DREG    r1, "r1 in is "
        DSTRING r0, "Sysvar name is "
 ]
        MOV     r2, r7
        ADR     r3, NullString
        BL      SReadVariable
        BVS     %FT90
        LDRNE   r0, [sp, r5]    ; Variable read OK so use default token
        ADDEQ   r0, sp, r5      ; Variable does not exist so use "Unset" token
        LDREQ   r0, [r0, #4]

 [ debugdirstore
        DSTRING r4, "Constructed path is now "
        DSTRING r1, "r1 tail is "
 ]

        ; One of the following situations exist on the stack:
        ; <FS>:
        ; <FS>::<disc>.$.blah
        ; <FS>:#<sp>::<disc>.$.blah
        ; In the last situation want to copy the tail over the 1st :
        LDRB    lr, [r1]
        TEQ     lr, #"#"
        MOVEQ   r2, r1
        SUBEQ   r1, r1, #1
        BLEQ    strcpy

        ; Now write the thing out (note tag set up above)
 [ debugdirstore
        DSTRING r0, "Tag:"
        DSTRING r4, "Subst param:"
 ]
        BL      message_write01
        BLVS    CopyErrorExternal

90
        ; Drop the accumulated stack frame
        ADD     sp, sp, r5
        EXIT

95
        ; Not enough stack for cat title
        addr    r0, ErrorBlock_NotEnoughStackForFSEntry
        BL      CopyError
        EXIT

NullString      DCB     0
                ALIGN

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; AlterMatchingDirs
;
; In    r1 = pointer to path tail (no FS prefix) to match
;       r2 = new prefix (0 to unset dir)
;       r3 = pointer to FS name (0, # or : terminated)
;
; Out   dirs prefixed with prefix altered or deleted as appropriate
;
; expected uses: from Service_DiscDismounted and rename

AlterMatchingDirs ENTRY "r0-r9"
 [ debugservice
        DSTRING r1, "AlterMatchingDirs(",cc
        DSTRING r2, ",",cc
        DSTRING r3, ",",cc
        DLINE   ")"
 ]

        MOV     r9, sp

        ; Find length of FS prefix
        MOV     r8, r3
10
        LDRB    lr, [r8], #1
        TEQ     lr, #"#"
        TEQNE   lr, #":"
        TEQNE   lr, #0
        BNE     %BT10

        ; Get a stack frame suitable for the sysvar names
        SUB     r4, r8, r3      ; r8 points to character beyond terminator, hence r4 = length+1
        ADD     r4, r4, #?FSW_Sysvar_Prefix + ?FSW_CSD_Suffix + 3
        BIC     r4, r4, #3
        SUB     sp, sp, r4

        ; Hold the path tail to match in r8
        MOV     r8, r1

        ; Copy the FSW_Sysvar_Prefix
        MOV     r1, sp
        addr    r2, FSW_Sysvar_Prefix
        BL      strcpy_advance

        ; Copy the FS name across
20
        LDRB    lr, [r3], #1
        TEQ     lr, #"#"
        TEQNE   lr, #":"
        TEQNE   lr, #0
        STRNEB  lr, [r1], #1
        BNE     %BT20

        ; Hold in r7 the place for the suffix
        MOV     r7, r1

        MOV     r5, #3          ; count from 3 to 0 for the suffices

        MOV     r6, sp

 [ debugservice
        DSTRING r6, "sysvar prefix is:"
        DSTRING r8, "tail to compare sysvars with:"
 ]

30
        ; Main loop:
        ; r0-r4 - used during loop
        ; r5 - count down of suffixes
        ; r6 - base stack pointer for main loop
        ; r7 - place to stick the suffix
        ; r8 - pointer to prefix peeled off string in
        ; r9 - stack pointer into routine


        ; Construct sysvar name on stack
        addr    r2, FSW_Sysvar_Suffixes
        LDR     r2, [r2, r5, ASL #2]
        addr    lr, Module_BaseAddr
        ADD     r2, r2, lr
        MOV     r1, r7
        BL      strcpy

        MOV     r0, sp
        addr    r3, anull
        BL      SReadVariableToBuffer
        BVS     %FT70

        MOV     r1, r8          ; the passed-in prefix
        MOV     r2, sp          ; The variable
        BL      IsAChild_advance
        BNE     %FT70

        ; Hot stuff! prefix prefixes path in an interesting way - let's do the business to it
        LDR     r1, [r9, #2*4]
        TEQ     r1, #0
        BNE     %FT40

        MOV     r0, r6
        MOV     r1, #NULL
        MOV     r2, #-1         ; destroy
        MOV     r3, #0
        MOV     r4, #VarType_String
        SWI     XOS_SetVarVal

        ; ignore errors back...
        B       %FT70

40
        ; Change prefix...

        ; drop stack enough to fit new prefix
        BL      strlen
        SUB     lr, r2, sp              ; length of prefix to remove
        SUBS    lr, r3, lr
        ADDPL   lr, lr, #3
        BICPL   lr, lr, #3
        SUBPL   sp, sp, lr

        SUB     r0, r2, r3
        MOV     r4, r0

50
        LDRB    lr, [r1], #1
        TEQ     lr, #0
        STRNEB  lr, [r0], #1
        BNE     %BT50

        MOV     r0, r6
        MOV     r1, r4
        MOV     r2, #0
        MOV     r3, #0
        MOV     r4, #VarType_String
        SWI     XOS_SetVarVal

        ; ignore errors back...

70
        ; restore loop stack and go around again
        MOV     sp, r6
        SUBS    r5, r5, #1
        BPL     %BT30

99
        MOV     sp, r9
        EXITS

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; UnsetMatchingDirs
;
; In    r2 = pointer to path
;
; Out   dirs prefixed with that path unset
;
; expect use: from Service_DiscDismounted

UnsetMatchingDirs ENTRY "r1-r3"
 [ debugservice
        DSTRING r2,"UnsetMatchingDirs(",cc
        DLINE   ")"
 ]

        MOV     r3, r2
        MOV     r1, r2

10
        LDRB    lr, [r1], #1
        TEQ     lr, #0          ; indicates absent FS prefix - not grokable
        BEQ     %FT99
        TEQ     lr, #"#"
        TEQ     lr, #":"
        BNE     %BT10

        TEQ     lr, #"#"
        SUBEQ   r1, r1, #1      ; only skip back to #, skip over a :
        MOV     r2, #0
        BL      AlterMatchingDirs

99
        EXITS

        END
